/*
 * Frida 脚本，用于精准 Hook EncryptorUtil 类
 * 目标: 监控 com.bytedance.frameworks.encryptor.EncryptorUtil 的所有方法调用，
 *       打印其输入参数和返回值，以捕获加解密操作。
 * 
 * 使用方法: frida -U -f com.zhiliaoapp.musically -l hook_encryptor_util.js --no-pause
 */

console.log("[*] EncryptorUtil 精准 Hook 脚本已启动。");

Java.perform(function () {
    try {
        const EncryptorUtil = Java.use('com.bytedance.frameworks.encryptor.EncryptorUtil');
        console.log("[+] 成功定位到类: com.bytedance.frameworks.encryptor.EncryptorUtil");

        // 获取该类的所有已声明的方法
        const methods = EncryptorUtil.class.getDeclaredMethods();
        console.log("[+] 发现 " + methods.length + " 个方法，正在进行 Hook...");

        // 遍历并 Hook 每一个方法
        methods.forEach(function (method) {
            const methodName = method.getName();
            
            // 通过反射获取方法的参数类型，这对于正确重载至关重要
            const parameterTypes = method.getParameterTypes();
            const methodSignature = parameterTypes.map(p => p.getName()).join(', ');

            console.log("  - 正在 Hook 方法: " + methodName + "(" + methodSignature + ")");

            // 使用 overload 获取特定签名的方法并进行 Hook
            EncryptorUtil[methodName].overload(...parameterTypes.map(p => p.getName())).implementation = function (...args) {
                console.log("\n============================================================");
                console.log("[*] 方法被调用: " + methodName + "(" + methodSignature + ")");
                console.log("------------------------------------------------------------");

                // 打印所有输入参数
                for (let i = 0; i < args.length; i++) {
                    let arg_value = args[i] ? args[i].toString() : "null";
                    // 对 byte[] 做特殊处理，因为加密操作中非常常见
                    if (parameterTypes[i].getName() === '[B') {
                        try {
                            // 尝试以 UTF-8 字符串形式打印，方便观察是否是 JSON 或其他文本
                            arg_value = `(字节数组, 长度=${args[i].length}) -> UTF8: '${Java.use('java.lang.String').$new(args[i])}'`;
                        } catch(e) {
                            // 如果转换失败，只打印长度和十六进制预览
                            arg_value = `(字节数组, 长度=${args[i].length})`;
                        }
                    }
                    console.log(`  [-] 参数[${i}] (${parameterTypes[i].getName()}): ${arg_value}`);
                }

                // 调用原始方法
                const retval = this[methodName](...args);

                // 打印返回值
                let retval_str = retval ? retval.toString() : "null";
                if (retval && retval.getClass && retval.getClass().getName() === '[B') {
                     try {
                        retval_str = `(字节数组, 长度=${retval.length}) -> UTF8: '${Java.use('java.lang.String').$new(retval)}'`;
                    } catch(e) {
                        retval_str = `(字节数组, 长度=${retval.length})`;
                    }
                }
                console.log("  [->] 返回值: " + retval_str);
                console.log("============================================================\n");

                return retval;
            };
        });
    } catch (e) {
        console.log("[!] Hook 失败: " + e.message);
    }
});